/*!
\copyright  Copyright (c) 2024-2025 Qualcomm Technologies International, Ltd.
            All Rights Reserved.
            Qualcomm Technologies International, Ltd. Confidential and Proprietary.
\file
\ingroup    audio_domain
\brief      Implementation of the UserEQ API

*/

#include "user_eq.h"
#include "user_eq_ctx.h"
#include "user_eq_operation.h"
#include "user_eq_callback_handlers.h"
#include "user_eq_data.h"
#include "user_eq_user_settings.h"
#include "user_eq_audio_config.h"
#include "user_eq_notification.h"

#include <logging.h>

/* Make the type used for message IDs available in debug tools */
LOGGING_PRESERVE_MESSAGE_TYPE(user_eq_messages_t)

ASSERT_MESSAGE_GROUP_NOT_OVERFLOWED(USER_EQ, USER_EQ_MESSAGE_END)


static uint8 userEq_InternalGetInitialPreset(void);
static bool userEq_InternalGetInitialBypassState(void);
static void userEq_InternalGetInitialGains(int16 *gains, uint8 number_of_gains);

static const user_eq_callbacks_t internal_user_eq_callbacks = 
{
    .GetInitialPreset = userEq_InternalGetInitialPreset,
    .GetInitialBypassState = userEq_InternalGetInitialBypassState,
    .GetInitialGains = userEq_InternalGetInitialGains,
};

bool UserEq_Init(Task init_task)
{
    UNUSED(init_task);
    
    UserEq_CtxInit();
    UserEq_DataLoad();
    UserEq_OperationInit();
    UserEq_NotificationInit();

    return TRUE;
}

void UserEq_RegisterCallbacks(const user_eq_callbacks_t *callbacks)
{
    UserEq_CtxGet()->callbacks = callbacks;
}

void UserEq_UseInternalCallbacks(void)
{
    UserEq_RegisterCallbacks(&internal_user_eq_callbacks);
}

bool UserEq_IsActive(void)
{
    return UserEq_OperationIsActive();
}

uint8 UserEq_GetNumberOfBands(void)
{
    return UserEq_CtxGet()->eq.user.number_of_bands;
}

uint8 UserEq_GetNumberOfEqBanks(void)
{
    return UserEq_CtxGet()->eq.number_of_presets + 2;
}

uint8 UserEq_PopulatePresets(uint8 *presets)
{
    return UserEq_AudioConfigPopulatePresets(presets);
}

bool UserEq_SelectPreset(uint8 preset)
{
    DEBUG_LOG_VERBOSE("UserEq_SelectPreset %d", preset);

    if(!UserEq_IsActive())
    {
        DEBUG_LOG_ERROR("UserEq_SelectPreset is not active");
        return FALSE;
    }

    UserEq_CtxGet()->eq.selected_eq_bank = preset;
    bool success = UserEq_OperationSelectPreset(preset);
    if(success)
    {
        UserEq_SettingsWriteToPsStorage(&UserEq_CtxGet()->eq);
    }


    return success;
}

uint8 UserEq_GetSelectedPreset(void)
{
    return UserEq_CtxGet()->eq.selected_eq_bank;
}

void UserEq_ApplyCurrentPresetAndGains(void)
{

}

bool UserEq_SetUserEqGains(uint8 start_band, uint8 end_band, int16 *gains)
{
    uint8 i;
    uint8 gain_index = 0;

    if(!UserEq_IsActive())
    {
        DEBUG_LOG_ERROR("UserEq_SetUserEqGains is not active");
        return FALSE;
    }

    if(end_band >= UserEq_GetNumberOfBands())
    {
        DEBUG_LOG_ERROR("UserEq_SetUserEqGains num_band %d is beyond maximum %d", end_band, UserEq_GetNumberOfBands()-1);
        return FALSE;
    }

    DEBUG_LOG_VERBOSE("UserEq_SetUserEqGains start band %d, end band %d, first gain %d",
                start_band, end_band, gains[0]);

    for(i = start_band; i <= end_band; i++)
    {
        UserEq_CtxGet()->gains[i] = gains[gain_index];
        UserEq_CtxGet()->eq.user.params[i].gain = gains[gain_index];
        DEBUG_LOG_VERBOSE("UserEq_SetUserEqGains gain %d set to %d", i, gains[gain_index]);
        ++gain_index;
    }

    bool success = UserEq_OperationSetGains(start_band, end_band, UserEq_CtxGet()->gains);
    if(success)
    {
        UserEq_SettingsWriteToPsStorage(&UserEq_CtxGet()->eq);
        UserEq_NotificationBandsUpdated(start_band, end_band);
    }

    return TRUE;
}

int16 UserEq_GetUserEqGain(uint8 band)
{
    int16 gain = 0;
    if(band < UserEq_GetNumberOfBands())
    {
        gain = UserEq_CtxGet()->gains[band];
    }
    return gain;
}

void UserEq_GetEqBandInformation(uint8 band, user_eq_parameter_set_t *param_set)
{
    if(band >= UserEq_CtxGet()->eq.user.number_of_bands)
    {
        Panic();
    }

    *param_set = UserEq_CtxGet()->eq.user.params[band];
}

bool UserEq_Bypass(bool enable_bypass)
{
    if(!UserEq_IsActive())
    {
        DEBUG_LOG_ERROR("UserEq_Bypass is not active");
        return FALSE;
    }

    if(enable_bypass)
    {
        UserEq_OperationSetBypass();
    }
    else
    {
        UserEq_OperationSelectPreset(UserEq_CtxGet()->eq.selected_eq_bank);
    }
    
    return TRUE;
}

void UserEq_HandleActivityIndication(bool is_active)
{
    const user_eq_callbacks_t *callbacks = UserEq_CtxGet()->callbacks;

    DEBUG_LOG_VERBOSE("UserEq_HandleActivityIndication %d", is_active);

    UserEq_CtxGet()->is_active = is_active;
    UserEq_NotificationEqIsAvailable(is_active);

    if(callbacks && callbacks->ActivityIndication)
    {
        callbacks->ActivityIndication(is_active);  
    }
}

uint8 UserEq_HandleInitialPreset(void)
{
    const user_eq_callbacks_t *callbacks = UserEq_CtxGet()->callbacks;
    uint8 eq_preset = 0;

    if(callbacks && callbacks->GetInitialPreset)
    {
        eq_preset = callbacks->GetInitialPreset();
    }

    DEBUG_LOG_VERBOSE("UserEq_HandleInitialPreset %d", eq_preset);

    UserEq_CtxGet()->eq.selected_eq_bank = eq_preset;

    return eq_preset;
}

bool UserEq_HandleInitialBypassState(void)
{
    const user_eq_callbacks_t *callbacks = UserEq_CtxGet()->callbacks;
    bool bypass_state = TRUE;

    if(callbacks && callbacks->GetInitialBypassState)
    {
        bypass_state = callbacks->GetInitialBypassState();
    }

    return bypass_state;
}

int16 *UserEq_HandleInitialGains(void)
{
    const user_eq_callbacks_t *callbacks = UserEq_CtxGet()->callbacks;

    if(callbacks && callbacks->GetInitialGains)
    {
        callbacks->GetInitialGains(UserEq_CtxGet()->gains, UserEq_GetNumberOfBands());
    }


    DEBUG_LOG_VERBOSE("UserEq_HandleInitialGains first gain %d", UserEq_CtxGet()->gains[0]);

    return UserEq_CtxGet()->gains;
}

static uint8 userEq_InternalGetInitialPreset(void)
{
    return UserEq_CtxGet()->eq.selected_eq_bank;
}

static bool userEq_InternalGetInitialBypassState(void)
{
    return FALSE;
}

static void userEq_InternalGetInitialGains(int16 *gains, uint8 number_of_gains)
{
    UNUSED(gains);
    UNUSED(number_of_gains);
}